import 'dart:convert';

import 'package:common_utils/common_utils.dart';
import 'package:dio/dio.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'package:x_core/net/base_entity.dart';
import 'package:x_core/res/x_constant.dart';

import 'interceptor/auth_interceptor.dart';
import 'net_exception.dart';

/// Created by XieXin on 2020/3/18.
/// Dio工具类
class DioHolder {
  ///连接超时时间
  static const int connectTimeout = 60;

  ///响应超时时间
  static const int receiveTimeout = 60;

  static late DioHolder _instance;
  static late Dio _dio;
  static late BaseOptions _options;
  static late String baseUrl;

  DioHolder._();

  factory DioHolder({String? baseUrl}) {
    if (!TextUtil.isEmpty(baseUrl)) {
      _options.baseUrl = baseUrl!;
    } else {
      _options.baseUrl = DioHolder.baseUrl;
    }
    return _instance;
  }

  static void init(String baseUrl) {
    DioHolder.baseUrl = baseUrl;
    _instance = DioHolder._();
    _options = BaseOptions(
      connectTimeout: const Duration(seconds: connectTimeout),
      receiveTimeout: const Duration(seconds: receiveTimeout),
      baseUrl: baseUrl,
      validateStatus: (status) {
        // 不使用http状态码判断状态，使用AdapterInterceptor来处理（适用于标准REST风格）
        return true;
      },
    );
    _dio = Dio(_options);

    /// 统一添加身份验证请求头
    _dio.interceptors.add(AuthInterceptor());

    /// 打印Log(生产模式去除)
    if (!XConstant.inProduction) {
      _dio.interceptors.add(PrettyDioLogger());
    }
  }

  static Dio get dio => _dio;

  Future<dynamic> get<T>(
    String url, {
    Map<String, dynamic>? queryParameters,
    Map<String, dynamic>? headers,
    bool showLoading = true,
    bool Function(NetException)? onError,
    CancelToken? cancelToken,
    bool isResponseDataEmptyHandle = true, //返回数据的data是否做空处理，true-是，false-否
  }) {
    return request(
      url,
      queryParameters: queryParameters,
      headers: headers,
      onError: onError,
      cancelToken: cancelToken,
      isResponseDataEmptyHandle: isResponseDataEmptyHandle,
    );
  }

  Future<dynamic> post<T>(
    String url, {
    Map<String, dynamic>? queryParameters,
    data,
    Map<String, dynamic>? headers,
    bool showLoading = true,
    bool Function(NetException)? onError,
    CancelToken? cancelToken,
    bool isResponseDataEmptyHandle = true, //返回数据的data是否做空处理，true-是，false-否
  }) {
    return request(
      url,
      method: "POST",
      queryParameters: queryParameters,
      data: data,
      headers: headers,
      onError: onError,
      cancelToken: cancelToken,
      isResponseDataEmptyHandle: isResponseDataEmptyHandle,
    );
  }

  Future<dynamic> delete<T>(
    String url, {
    Map<String, dynamic>? queryParameters,
    data,
    Map<String, dynamic>? headers,
    bool showLoading = true,
    bool Function(NetException)? onError,
    CancelToken? cancelToken,
    bool isResponseDataEmptyHandle = true, //返回数据的data是否做空处理，true-是，false-否
  }) {
    return request(
      url,
      method: "DELETE",
      queryParameters: queryParameters,
      data: data,
      headers: headers,
      onError: onError,
      cancelToken: cancelToken,
      isResponseDataEmptyHandle: isResponseDataEmptyHandle,
    );
  }

  Future<dynamic> put<T>(
    String url, {
    Map<String, dynamic>? queryParameters,
    data,
    Map<String, dynamic>? headers,
    bool showLoading = true,
    bool Function(NetException)? onError,
    CancelToken? cancelToken,
    bool isResponseDataEmptyHandle = true, //返回数据的data是否做空处理，true-是，false-否
  }) {
    return request(
      url,
      method: "PUT",
      queryParameters: queryParameters,
      data: data,
      headers: headers,
      onError: onError,
      cancelToken: cancelToken,
      isResponseDataEmptyHandle: isResponseDataEmptyHandle,
    );
  }

  Future<dynamic> request(
    String url, {
    String method = "GET",
    Map<String, dynamic>? queryParameters,
    data,
    Map<String, dynamic>? headers,
    bool Function(NetException)? onError,
    CancelToken? cancelToken,
    bool isResponseDataEmptyHandle = true, //返回数据的data是否做空处理，true-是，false-否
  }) async {
    try {
      Options options = Options()
        ..method = method
        ..headers = headers;

      data = _convertRequestData(data);

      Response response = await _dio.request(
        url,
        queryParameters: queryParameters,
        cancelToken: cancelToken,
        data: data,
        options: options,
      );
      return _handleResponse(
        response,
        isResponseDataEmptyHandle: isResponseDataEmptyHandle,
      );
    } catch (e) {
      var exception = NetException.from(e);
      if (onError?.call(exception) != true) {
        throw exception;
      }
    }
    return null;
  }

  _convertRequestData(data) {
    if (data != null) {
      data = jsonDecode(jsonEncode(data));
    }
    return data;
  }

  ///请求响应内容处理
  dynamic _handleResponse(
    Response response, {
    bool isResponseDataEmptyHandle = true, //返回数据的data是否做空处理，true-是，false-否
  }) {
    if (response.statusCode == 200) {
      try {
        BaseEntity entity = BaseEntity.fromJson(response.data);
        return _handleBusinessResponse(
          entity,
          isResponseDataEmptyHandle: isResponseDataEmptyHandle,
        );
      } catch (e) {
        LogUtil.e(e.toString());
        var exception = NetException(
            NetException.parseException, NetException.parseExceptionStr);
        throw exception;
      }
    } else {
      var exception =
          NetException(response.statusCode, NetException.unknownExceptionStr);
      throw exception;
    }
  }

  ///业务内容处理
  dynamic _handleBusinessResponse(
    BaseEntity entity, {
    bool isResponseDataEmptyHandle = true, //返回数据的data是否做空处理，true-是，false-否
  }) {
    if (entity.code == BaseEntity.okCode) {
      if (!isResponseDataEmptyHandle) {
        return entity.data;
      }
      if (entity.data != null) {
        return entity.data;
      } else {
        var exception = NetException(
            NetException.dataException, NetException.dataExceptionStr);
        throw exception;
      }
    } else {
      var exception = NetException(entity.code, entity.message);
      throw exception;
    }
  }

  ///下载
  void download(
    String urlPath,
    String savePath, {
    ProgressCallback? onReceiveProgress,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    bool deleteOnError = true,
    String lengthHeader = Headers.contentLengthHeader,
    data,
    Options? options,
    Function()? onSuccess,
    Function(NetException e)? onError,
  }) {
    Dio().download(
      urlPath,
      savePath,
      onReceiveProgress: (int count, int total) {
        LogUtil.v("download ========> count: $count total: $total");
        if (onReceiveProgress != null) onReceiveProgress(count, total);
      },
      queryParameters: queryParameters,
      cancelToken: cancelToken,
      deleteOnError: true,
      lengthHeader: Headers.contentLengthHeader,
      data: data,
      options: options,
    ).then((value) {
      if (onSuccess != null) onSuccess();
    }).onError((error, stackTrace) {
      //请求失败
      var exception = NetException.from(error);
      if (onError?.call(exception) != true) {
        throw exception;
      }
    });
  }
}
